package com.jf.identity.datasource;

import com.jf.identity.config.ExamConfig;
import com.jf.identity.config.MachineConfig;
import com.jf.identity.entity.ExamInfo;
import org.apache.commons.dbcp2.BasicDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author FCG
 */
@Component
public class TargetDataSource {
    private final static String driverClassName = "com.mysql.jdbc.Driver";
    private final Logger logger = LoggerFactory.getLogger(getClass());
    private static String dbConnUrlStr
            = "?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false" +
            "&allowMultiQueries=true&useSSL=true";
    private static String dataBaseHost = "192.168.20.195";
    private static String dataBasePort = "3306";
    private static String userName = "root";
    private static String pwd = "jfkjyfb";
    public final static String JF_VIS_DB = "jf_vis_db";
    public final static String JF_DC_DB = "jf_dc_db";

    /**
     * 根据machineConfig中的配置，生成多个待用数据源
     *
     * @param machineConfig machineConfig
     * @return 多个数据源
     */
    public Map<String, DataSource> getTargetDataSource(MachineConfig machineConfig, ExamConfig examConfig) {
        Objects.requireNonNull(machineConfig, "machineConfig can't be null");
        Map<String, DataSource> targetDataSource = new HashMap<>();
        List<ExamInfo> examInfos = examConfig.getExamInfos();
        //数据库连接字符串
        //jdbc:mysql://192.168.20.195:3306/###?user=root&amp;password=jfkjyfb&amp;useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;failOverReadOnly=false&amp;allowMultiQueries=true
        String tempUrl = machineConfig.getDbConnectionUrl();
        //配置 分库
        for (ExamInfo examInfo : examInfos) {
            //考试计划id
            String examId = examInfo.getExamId();
            //分库 jf_vis_db_20181009
            String url = tempUrl.replace("###", TargetDataSource.JF_VIS_DB + "_" + examId);
            BasicDataSource jfVisDb = getDataSource();
            jfVisDb.setUrl(url);
            targetDataSource.put(TargetDataSource.JF_VIS_DB + examId, jfVisDb);
            logger.info("设置数据源:{}", url);
        }
        //配置 基础库
        BasicDataSource jfDcDb = getDataSource();
        String url = tempUrl.replace("###", TargetDataSource.JF_DC_DB);
        jfDcDb.setUrl(url);
        targetDataSource.put(TargetDataSource.JF_DC_DB, jfDcDb);
//        //配置 静态库
//        DataSource jfVisDb = getDefaultDataSource(machineConfig);
//        targetDataSource.put(TargetDataSource.JF_VIS_DB, jfVisDb);
        return targetDataSource;
    }

    public DataSource getDefaultDataSource(MachineConfig machineConfig) {
        String tempUrl = machineConfig.getDbConnectionUrl();
        //默认数据库 jf_vis_db
        String url = tempUrl.replace("###", "");
        BasicDataSource dataSource = getDataSource();
        dataSource.setUrl(url);
        return dataSource;
    }

    /**
     * 按照examId动态获取jf_vis_db_考试计划 分库
     *
     * @param machineConfig 配置文件
     * @param examId        考试计划
     * @return 数据源
     */
    public DataSource getDynamicVisDataSource(MachineConfig machineConfig, String examId) {
        BasicDataSource dataSource = getDataSource();
        String tempUrl = machineConfig.getDbConnectionUrl();
        //数据库 jf_vis_db_20181009
        String url = tempUrl.replace("###", TargetDataSource.JF_VIS_DB + "_" + examId);
        dataSource.setUrl(url);
        return dataSource;
    }

    /**
     * 设置一些通用配置
     *
     * @return druid 数据源
     */
    private BasicDataSource getDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
//        dataSource.setUsername(userName);
//        dataSource.setPassword(pwd);
        dataSource.setDriverClassName(driverClassName);
        //配置初始化大小、最小、最大
        dataSource.setInitialSize(0);
        dataSource.setMinIdle(10);
        dataSource.setMaxTotal(500);
        //配置获取连接等待超时的时间
        dataSource.setMaxWaitMillis(60000);
        //这里建议配置为TRUE，防止取到的连接不可用。获取链接的时候，不校验是否可用，开启会有损性能
        dataSource.setTestOnBorrow(true);
        //归还链接到连接池的时候校验链接是否可用
        dataSource.setTestOnReturn(true);
        //此项配置为true即可，不影响性能，并且保证安全性。
        // 意义为：申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效
        dataSource.setTestWhileIdle(true);
        //配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位毫秒
        dataSource.setTimeBetweenEvictionRunsMillis(60000);
        //配置一个连接在池中最小生存的时间，单位毫秒
        dataSource.setMinEvictableIdleTimeMillis(300000);
        //链接使用超过时间限制是否回收
        dataSource.setRemoveAbandonedOnBorrow(true);
        //超过时间限制时间（单位秒），目前为5分钟，如果有业务处理时间超过5分钟，可以适当调整。
        dataSource.setRemoveAbandonedTimeout(300);
        //链接回收的时候控制台打印信息，测试环境可以加上true，线上环境false。会影响性能。
        dataSource.setLogAbandoned(true);
        //验证连接有效与否的SQL，不同的数据配置不同
        dataSource.setValidationQuery("SELECT 1");
        return dataSource;
    }
}




















